package com.test.demo.filter;


import com.test.demo.Util.HtmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * 参数校验过滤器（针对json报文请求） 1.获取请求参数；
 * 2.对获取到的请求参数进行处理（解密、字符串替、请求参数分类截取等等）；
 * 3.把处理后的参数放回到请求列表里面
 *
 * @author zx
 * @version 1.0
 */
public class ValidatorFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger(ValidatorFilter.class);
    /**
     * 不需要走过滤器的请求地址
     */
    @Value("#{'${myFilter:passUrl}'.split(',')}")
    private List<String> list;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("ValidatorFilter 过滤器初始化....");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpServletRequest request = (HttpServletRequest) req;
        MyHttpServletRequestWapper myWapper = new MyHttpServletRequestWapper(request);

        // 请求的url
        String url = request.getRequestURI();
        if (url.startsWith(request.getContextPath())) {
            url = url.substring(request.getContextPath().length(), url.length());
        }
        log.info("------:请求的url={}", url);
        if (!(StringUtils.isEmpty(url)) && !(CollectionUtils.isEmpty(list))) {
            //不做过滤的请求地址
            PathMatcher matcher = new AntPathMatcher();
            for (String s : list) {
                //  if (url.matches(s)) {
                if (matcher.match(s, url)) {
                    log.info("请求的url={}为开放地址", url);
                    //直接放行
                    chain.doFilter(myWapper, response);
                }
            }
        }
        //获取请求参数
        Map<String, String[]> parameterMap = myWapper.getParameterMap();
        //可操作的map集合
        Map<String, String> map = myWapper.getMap(parameterMap);
        //进行简单的校验参数是否合法
        String badStr = paramValidate(map);
        if (!StringUtils.isEmpty(badStr)) {
            log.warn("入参检验不通过");
            try {
                sendStartAuthentication(request, response, "111",
                        "入参不合法" + ": " + badStr);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return;
        }
        chain.doFilter(myWapper, response);

    }

    @Override
    public void destroy() {
        log.info("ValidatorFilter  过滤器结束...");
    }


    /**
     * 对字符进行简单的检验
     *
     * @param map 入参集合
     * @return 返回包含的不合法字符
     */
    protected String paramValidate(Map<String, String> map) {

        //过滤掉的sql关键字，可以手动添加
        String badStr = "'|and |exec |execute |insert |select| delete |update|count|drop|*|%|chr|mid|master|truncate|" +
                "char |declare |sitename |net user |xp_cmdshell | or |-|+|like'|and|exec |execute |insert |create |drop |" +
                "table|from|grant|use|group_concat|column_name|" +
                "information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|" +
                "chr|mid|master|truncate|char|declare|or|--|+|like|//|/|%|#|" +
                "<html>|<script>|<div>|<|>";
        String[] badStrs = badStr.split("\\|");

        for (String key : map.keySet()) {
            HashSet<String> badSet = new HashSet<>(Arrays.asList(badStrs));
            String values = map.get(key);
            if (null == values) {
                continue;
            }
            badSet.retainAll(Arrays.asList(values.split(",")));
            if (!CollectionUtils.isEmpty(badSet)) {
                log.warn("存在不合法的参数： {}", badSet.toString());
                return badSet.toString().replaceAll("<","\"<\"").replaceAll(">","\">\"");
            }
        }
        return null;
    }


    public void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, String code, String message) throws Exception {
        Map<String, Object> responseMap = new HashMap();
        responseMap.put("success", false);
        responseMap.put("code", code);
        responseMap.put("message", message);
        response.setStatus(HttpServletResponse.SC_OK);
        HtmlUtil.writerJson(response, responseMap);
    }

}
